import { Parser } from 'binary-parser';
const events = require('events');
const StreamFrame = require('./tcpframe');

var packetParser = new Parser()
	.uint8('type')
	.int32('packetLength')
	.buffer('data', {
		length: 'packetLength',
	});

class FrameSocket {
	constructor(nsock) {
		this._socket = nsock;
		this._debugDumpLength = 100;
		this._defaultReconnectWhenIdle = 300;
		this._connectTarget = undefined;
		this._isConnected = false;
		this._isClient = false;

		this._socket._debug = () => {};

		var frameParser = new StreamFrame(this._socket);
		frameParser.set('lengthSize', 4);
		frameParser.set('offset', 1);
		frameParser.set('bigEndian', true);
		frameParser.on(
			'data',
			async function(data) {
				this._resetClock();

				var packet = packetParser.parse(data);
				if (this._debugDumpLength != 0) {
					var ds = packet.data.toString();
					const len = this._debugDumpLength;
					console.log('frame: [%d] %s %s', packet.data.length, ds.substr(0, len), ds.length > len ? '...' : '');
				}

				this._socket.emit('packet', packet);
			}.bind(this)
		);

		this.on('timeout', function() {
			console.log('Connection timeout');
		});
		this.on('end', function() {
			console.log('Connection end');
		});
		this.on('error', function(err) {
			console.log('connect error: %s', err);
		});

		this.on(
			'connect',
			function() {
				console.log('Connection ok');
				this._resetClock();
				this._isConnected = true;
			}.bind(this)
		);

		this.on(
			'close',
			function() {
				console.log('Connection closed');
				this._isConnected = false;
				if (!this._exit && this._connectTarget) {
					setTimeout(
						function() {
							console.log('auto reconnect:', JSON.stringify(this._connectTarget));
							this.connect(this._connectTarget.port, this._connectTarget.host);
						}.bind(this),
						3 * 1000
					);
				} else {
					if (this._tmResetConnection) clearTimeout(this._tmResetConnection);
				}
			}.bind(this)
		);
	}

	_resetClock() {
		if (!this._isClient) return;
		if (this._tmResetConnection) {
			clearTimeout(this._tmResetConnection);
		}

		var dd = this._defaultReconnectWhenIdle;
		this._tmResetConnection = setTimeout(() => {
			console.log('**idle too much, reconnect**', dd);
			this._socket.destroy();
			this._tmResetConnection = undefined;
		}, this._defaultReconnectWhenIdle * 1000);
	}

	autoConnect(port, host) {
		this._isClient = true;
		this._connectTarget = { port: port, host: host };
		this.connect(port, host);
	}

	close() {
		this._exit = true;
		this._socket.destroy();
	}

	isConnected() {
		return this._isConnected;
	}

	sendJSON(obj) {
		this.sendString(JSON.stringify(obj));
	}

	sendString(str) {
		//console.log('send string: [%d] %s', str.length, str);
		var head = Buffer.alloc(5);
		var body = new Buffer(str);
		head.writeInt8(1);
		head.writeInt32BE(body.length, 1);
		this._socket.write(head);
		this._socket.write(body);
	}
}

var delegates = ['connect', 'on', 'once', 'removeListener', 'removeAllListeners', 'end', 'setTimeout', 'setKeepAlive'];
delegates.forEach(function(method) {
	FrameSocket.prototype[method] = function() {
		this._socket[method].apply(this._socket, arguments);
		return this;
	};
});

module.exports = FrameSocket;
